class Akismet_REST_API { /** * Register the REST API routes. */ public static function init() { if ( ! function_exists( 'register_rest_route' ) ) { // The REST API wasn't integrated into core until 4.4, and we support 4.0+ (for now). return false; } register_rest_route( 'akismet/v1', '/key', array( array( 'methods' => WP_REST_Server::READABLE, 'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ), 'callback' => array( 'Akismet_REST_API', 'get_key' ), ), array( 'methods' => WP_REST_Server::EDITABLE, 'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ), 'callback' => array( 'Akismet_REST_API', 'set_key' ), 'args' => array( 'key' => array( 'required' => true, 'type' => 'string', 'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ), 'description' => __( 'A 12-character Akismet API key. Available at akismet.com/account', 'akismet' ), ), ), ), array( 'methods' => WP_REST_Server::DELETABLE, 'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ), 'callback' => array( 'Akismet_REST_API', 'delete_key' ), ), ) ); register_rest_route( 'akismet/v1', '/settings/', array( array( 'methods' => WP_REST_Server::READABLE, 'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ), 'callback' => array( 'Akismet_REST_API', 'get_settings' ), ), array( 'methods' => WP_REST_Server::EDITABLE, 'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ), 'callback' => array( 'Akismet_REST_API', 'set_boolean_settings' ), 'args' => array( 'akismet_strictness' => array( 'required' => false, 'type' => 'boolean', 'description' => __( 'If true, Akismet will automatically discard the worst spam automatically rather than putting it in the spam folder.', 'akismet' ), ), 'akismet_show_user_comments_approved' => array( 'required' => false, 'type' => 'boolean', 'description' => __( 'If true, show the number of approved comments beside each comment author in the comments list page.', 'akismet' ), ), 'akismet_enable_mcp_access' => array( 'required' => false, 'type' => 'boolean', 'description' => __( 'If true, allow MCP clients to access Akismet data and functionality.', 'akismet' ), ), ), ), ) ); register_rest_route( 'akismet/v1', '/stats', array( 'methods' => WP_REST_Server::READABLE, 'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ), 'callback' => array( 'Akismet_REST_API', 'get_stats' ), 'args' => array( 'interval' => array( 'required' => false, 'type' => 'string', 'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_interval' ), 'description' => __( 'The time period for which to retrieve stats. Options: 60-days, 6-months, all', 'akismet' ), 'default' => 'all', ), ), ) ); register_rest_route( 'akismet/v1', '/stats/(?P[\w+])', array( 'args' => array( 'interval' => array( 'description' => __( 'The time period for which to retrieve stats. Options: 60-days, 6-months, all', 'akismet' ), 'type' => 'string', ), ), array( 'methods' => WP_REST_Server::READABLE, 'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ), 'callback' => array( 'Akismet_REST_API', 'get_stats' ), ), ) ); register_rest_route( 'akismet/v1', '/alert', array( array( 'methods' => WP_REST_Server::READABLE, 'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ), 'callback' => array( 'Akismet_REST_API', 'get_alert' ), 'args' => array( 'key' => array( 'required' => false, 'type' => 'string', 'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ), 'description' => __( 'A 12-character Akismet API key. Available at akismet.com/account', 'akismet' ), ), ), ), array( 'methods' => WP_REST_Server::EDITABLE, 'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ), 'callback' => array( 'Akismet_REST_API', 'set_alert' ), 'args' => array( 'key' => array( 'required' => false, 'type' => 'string', 'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ), 'description' => __( 'A 12-character Akismet API key. Available at akismet.com/account', 'akismet' ), ), ), ), array( 'methods' => WP_REST_Server::DELETABLE, 'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ), 'callback' => array( 'Akismet_REST_API', 'delete_alert' ), 'args' => array( 'key' => array( 'required' => false, 'type' => 'string', 'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ), 'description' => __( 'A 12-character Akismet API key. Available at akismet.com/account', 'akismet' ), ), ), ), ) ); register_rest_route( 'akismet/v1', '/webhook', array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( 'Akismet_REST_API', 'receive_webhook' ), 'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ), ) ); } /** * Get the current Akismet API key. * * @param WP_REST_Request $request * @return WP_Error|WP_REST_Response */ public static function get_key( $request = null ) { return rest_ensure_response( Akismet::get_api_key() ); } /** * Set the API key, if possible. * * @param WP_REST_Request $request * @return WP_Error|WP_REST_Response */ public static function set_key( $request ) { if ( defined( 'WPCOM_API_KEY' ) ) { return rest_ensure_response( new WP_Error( 'hardcoded_key', __( 'This site\'s API key is hardcoded and cannot be changed via the API.', 'akismet' ), array( 'status' => 409 ) ) ); } $new_api_key = $request->get_param( 'key' ); if ( ! self::key_is_valid( $new_api_key ) ) { return rest_ensure_response( new WP_Error( 'invalid_key', __( 'The value provided is not a valid and registered API key.', 'akismet' ), array( 'status' => 400 ) ) ); } update_option( 'wordpress_api_key', $new_api_key ); return self::get_key(); } /** * Unset the API key, if possible. * * @param WP_REST_Request $request * @return WP_Error|WP_REST_Response */ public static function delete_key( $request ) { if ( defined( 'WPCOM_API_KEY' ) ) { return rest_ensure_response( new WP_Error( 'hardcoded_key', __( 'This site\'s API key is hardcoded and cannot be deleted.', 'akismet' ), array( 'status' => 409 ) ) ); } delete_option( 'wordpress_api_key' ); return rest_ensure_response( true ); } /** * Get the Akismet settings. * * @param WP_REST_Request $request * @return WP_Error|WP_REST_Response */ public static function get_settings( $request = null ) { return rest_ensure_response( array( 'akismet_strictness' => ( get_option( 'akismet_strictness', '1' ) === '1' ), 'akismet_show_user_comments_approved' => ( get_option( 'akismet_show_user_comments_approved', '1' ) === '1' ), 'akismet_enable_mcp_access' => ( get_option( 'akismet_enable_mcp_access', '0' ) === '1' ), ) ); } /** * Update the Akismet settings. * * @param WP_REST_Request $request * @return WP_Error|WP_REST_Response */ public static function set_boolean_settings( $request ) { foreach ( array( 'akismet_strictness', 'akismet_show_user_comments_approved', 'akismet_enable_mcp_access', ) as $setting_key ) { $setting_value = $request->get_param( $setting_key ); if ( is_null( $setting_value ) ) { // This setting was not specified. continue; } // From 4.7+, WP core will ensure that these are always boolean // values because they are registered with 'type' => 'boolean', // but we need to do this ourselves for prior versions. $setting_value = self::parse_boolean( $setting_value ); update_option( $setting_key, $setting_value ? '1' : '0' ); } return self::get_settings(); } /** * Parse a numeric or string boolean value into a boolean. * * @param mixed $value The value to convert into a boolean. * @return bool The converted value. */ public static function parse_boolean( $value ) { switch ( $value ) { case true: case 'true': case '1': case 1: return true; case false: case 'false': case '0': case 0: return false; default: return (bool) $value; } } /** * Get the Akismet stats for a given time period. * * Possible `interval` values: * - all * - 60-days * - 6-months * * @param WP_REST_Request $request * @return WP_Error|WP_REST_Response */ public static function get_stats( $request ) { $api_key = Akismet::get_api_key(); $interval = $request->get_param( 'interval' ); $stat_totals = array(); $request_args = array( 'blog' => get_option( 'home' ), 'key' => $api_key, 'from' => $interval, ); $request_args = apply_filters( 'akismet_request_args', $request_args, 'get-stats' ); $response = Akismet::http_post( Akismet::build_query( $request_args ), 'get-stats' ); if ( ! empty( $response[1] ) ) { $stat_totals[ $interval ] = json_decode( $response[1] ); } return rest_ensure_response( $stat_totals ); } /** * Get the current alert code and message. Alert codes are used to notify the site owner * if there's a problem, like a connection issue between their site and the Akismet API, * invalid requests being sent, etc. * * @param WP_REST_Request $request * @return WP_Error|WP_REST_Response */ public static function get_alert( $request ) { return rest_ensure_response( array( 'code' => get_option( 'akismet_alert_code' ), 'message' => get_option( 'akismet_alert_msg' ), ) ); } /** * Update the current alert code and message by triggering a call to the Akismet server. * * @param WP_REST_Request $request * @return WP_Error|WP_REST_Response */ public static function set_alert( $request ) { delete_option( 'akismet_alert_code' ); delete_option( 'akismet_alert_msg' ); // Make a request so the most recent alert code and message are retrieved. Akismet::verify_key( Akismet::get_api_key() ); return self::get_alert( $request ); } /** * Clear the current alert code and message. * * @param WP_REST_Request $request * @return WP_Error|WP_REST_Response */ public static function delete_alert( $request ) { delete_option( 'akismet_alert_code' ); delete_option( 'akismet_alert_msg' ); return self::get_alert( $request ); } private static function key_is_valid( $key ) { $request_args = array( 'key' => $key, 'blog' => get_option( 'home' ), ); $request_args = apply_filters( 'akismet_request_args', $request_args, 'verify-key' ); $response = Akismet::http_post( Akismet::build_query( $request_args ), 'verify-key' ); if ( $response[1] == 'valid' ) { return true; } return false; } public static function privileged_permission_callback() { return current_user_can( 'manage_options' ); } /** * For calls that Akismet.com makes to the site to clear outdated alert codes, use the API key for authorization. */ public static function remote_call_permission_callback( $request ) { $local_key = Akismet::get_api_key(); return $local_key && ( strtolower( $request->get_param( 'key' ) ?? '' ) === strtolower( $local_key ) ); } public static function sanitize_interval( $interval, $request, $param ) { $interval = trim( $interval ); $valid_intervals = array( '60-days', '6-months', 'all' ); if ( ! in_array( $interval, $valid_intervals ) ) { $interval = 'all'; } return $interval; } public static function sanitize_key( $key, $request, $param ) { return trim( $key ); } /** * Process a webhook request from the Akismet servers. * * @param WP_REST_Request $request * @return WP_Error|WP_REST_Response */ public static function receive_webhook( $request ) { Akismet::log( array( 'Webhook request received', $request->get_body() ) ); /** * The request body should look like this: * array( * 'key' => '1234567890abcd', * 'endpoint' => '[comment-check|submit-ham|submit-spam]', * 'comments' => array( * array( * 'guid' => '[...]', * 'result' => '[true|false]', * 'comment_author' => '[...]', * [...] * ), * array( * 'guid' => '[...]', * [...], * ), * [...] * ) * ) * * Multiple comments can be included in each request, and the only truly required * field for each is the guid, although it would be friendly to include also * comment_post_ID, comment_parent, and comment_author_email, if possible to make * searching easier. */ // The response will include statuses for the result of each comment that was supplied. $response = array( 'comments' => array(), ); $endpoint = $request->get_param( 'endpoint' ); switch ( $endpoint ) { case 'comment-check': $webhook_comments = $request->get_param( 'comments' ); if ( ! is_array( $webhook_comments ) ) { return rest_ensure_response( new WP_Error( 'malformed_request', __( 'The \'comments\' parameter must be an array.', 'akismet' ), array( 'status' => 400 ) ) ); } foreach ( $webhook_comments as $webhook_comment ) { $guid = $webhook_comment['guid']; if ( ! $guid ) { // Without the GUID, we can't be sure that we're matching the right comment. // We'll make it a rule that any comment without a GUID is ignored intentionally. continue; } // Search on the fields that are indexed in the comments table, plus the GUID. // The GUID is the only thing we really need to search on, but comment_meta // is not indexed in a useful way if there are many many comments. This // should help narrow it down first. $queryable_fields = array( 'comment_post_ID' => 'post_id', 'comment_parent' => 'parent', 'comment_author_email' => 'author_email', ); $query_args = array(); $query_args['status'] = 'any'; $query_args['meta_key'] = 'akismet_guid'; $query_args['meta_value'] = $guid; foreach ( $queryable_fields as $queryable_field => $wp_comment_query_field ) { if ( isset( $webhook_comment[ $queryable_field ] ) ) { $query_args[ $wp_comment_query_field ] = $webhook_comment[ $queryable_field ]; } } $comments_query = new WP_Comment_Query( $query_args ); $comments = $comments_query->comments; if ( ! $comments ) { // Unexpected, although the comment could have been deleted since being submitted. Akismet::log( 'Webhook failed: no matching comment found.' ); $response['comments'][ $guid ] = array( 'status' => 'error', 'message' => __( 'Could not find matching comment.', 'akismet' ), ); continue; } if ( count( $comments ) > 1 ) { // Two comments shouldn't be able to match the same GUID. Akismet::log( 'Webhook failed: multiple matching comments found.', $comments ); $response['comments'][ $guid ] = array( 'status' => 'error', 'message' => __( 'Multiple comments matched request.', 'akismet' ), ); continue; } else { // We have one single match, as hoped for. Akismet::log( 'Found matching comment.', $comments ); $comment = $comments[0]; $current_status = wp_get_comment_status( $comment ); $result = $webhook_comment['result']; if ( 'true' == $result ) { Akismet::log( 'Comment should be spam' ); // The comment should be classified as spam. if ( 'spam' != $current_status ) { // The comment is not classified as spam. If Akismet was the one to act on it, move it to spam. if ( Akismet::last_comment_status_change_came_from_akismet( $comment->comment_ID ) ) { Akismet::log( 'Comment is not spam; marking as spam.' ); wp_spam_comment( $comment ); Akismet::update_comment_history( $comment->comment_ID, '', 'webhook-spam' ); } else { Akismet::log( 'Comment is not spam, but it has already been manually handled by some other process.' ); Akismet::update_comment_history( $comment->comment_ID, '', 'webhook-spam-noaction' ); } } } elseif ( 'false' == $result ) { Akismet::log( 'Comment should be ham' ); // The comment should be classified as ham. if ( 'spam' == $current_status ) { Akismet::log( 'Comment is spam.' ); // The comment is classified as spam. If Akismet was the one to label it as spam, unspam it. if ( Akismet::last_comment_status_change_came_from_akismet( $comment->comment_ID ) ) { Akismet::log( 'Akismet marked it as spam; unspamming.' ); wp_unspam_comment( $comment ); akismet::update_comment_history( $comment->comment_ID, '', 'webhook-ham' ); } else { Akismet::log( 'Comment is not spam, but it has already been manually handled by some other process.' ); Akismet::update_comment_history( $comment->comment_ID, '', 'webhook-ham-noaction' ); } } else if ( 'unapproved' == $current_status ) { Akismet::log( 'Comment is pending.' ); // The comment is in Pending. If Akismet was the one to put it there, approve it (but only if the site // settings dictate that). if ( Akismet::last_comment_status_change_came_from_akismet( $comment->comment_ID ) ) { Akismet::log( 'Akismet marked it as Pending; approving.' ); if ( check_comment( $comment->comment_author, $comment->comment_author_email, $comment->comment_author_url, $comment->comment_content, $comment->comment_author_IP, $comment->comment_agent, $comment->comment_type ) ) { wp_set_comment_status( $comment->comment_ID, 1 ); } akismet::update_comment_history( $comment->comment_ID, '', 'webhook-ham' ); } else { Akismet::log( 'Comment is not spam, but it has already been manually handled by some other process.' ); Akismet::update_comment_history( $comment->comment_ID, '', 'webhook-ham-noaction' ); } } $moderation_email_was_delayed = get_comment_meta( $comment->comment_ID, 'akismet_delayed_moderation_email', true ); if ( $moderation_email_was_delayed ) { Akismet::log( 'Moderation email was delayed for comment #' . $comment->comment_ID . '; sending now.' ); delete_comment_meta( $comment->comment_ID, 'akismet_delayed_moderation_email' ); wp_new_comment_notify_moderator( $comment->comment_ID ); wp_new_comment_notify_postauthor( $comment->comment_ID ); } delete_comment_meta( $comment->comment_ID, 'akismet_delay_moderation_email' ); } $response['comments'][ $guid ] = array( 'status' => 'success' ); } } break; case 'submit-ham': case 'submit-spam': // Nothing to do for submit-ham or submit-spam. break; default: // Unsupported endpoint. break; } /** * Allow plugins to do things with a successfully processed webhook request, like logging. * * @since 5.3.2 * * @param WP_REST_Request $request The REST request object. */ do_action( 'akismet_webhook_received', $request ); Akismet::log( 'Done processing webhook.' ); return rest_ensure_response( $response ); } } /** * LazyBlocks dummy. * * @package lazyblocks */ if ( ! defined( 'ABSPATH' ) ) { exit; } /** * LazyBlocks_Dummy class. Class to work with LazyBlocks Controls. */ class LazyBlocks_Dummy { /** * Name of option that will prevent multiple example blocks creation. * * @var string */ private static $option_name = 'lzb_dummy_added'; /** * LazyBlocks_Dummy constructor. */ public function __construct() {} /** * Add dummy block */ public static function add() { // Check if already added example block. if ( get_option( self::$option_name, false ) ) { return; } // Check if any blocks already added. $blocks = get_posts( array( 'post_type' => 'lazyblocks', 'numberposts' => 1, 'post_status' => 'any', 'fields' => 'ids', ) ); if ( count( $blocks ) > 0 ) { return; } // Create new post. $post_id = wp_insert_post( array( 'post_title' => esc_attr__( 'Example Block', 'lazy-blocks' ), 'post_status' => 'draft', 'post_type' => 'lazyblocks', ) ); $code = '{{#if image.url}}

{{image.alt}}

{{#if button-label}}

{{button-label}}

{{/if}} {{else}}

Image is required to show this block content.

{{/if}}'; if ( $post_id ) { lazyblocks()->blocks()->save_meta_boxes( $post_id, array( 'lazyblocks_controls' => array( 'control_005ad74de2' => array( 'type' => 'image', 'name' => 'image', 'default' => '', 'label' => 'Image', 'help' => '', 'child_of' => '', 'placement' => 'inspector', 'width' => '100', 'hide_if_not_selected' => 'false', 'save_in_meta' => 'false', 'save_in_meta_name' => '', 'required' => 'false', 'placeholder' => '', 'characters_limit' => '', ), 'control_1729664f06' => array( 'type' => 'text', 'name' => 'button-label', 'default' => '', 'label' => 'Button Label', 'help' => '', 'child_of' => '', 'placement' => 'inspector', 'width' => '100', 'hide_if_not_selected' => 'false', 'save_in_meta' => 'false', 'save_in_meta_name' => '', 'required' => 'false', 'placeholder' => '', 'characters_limit' => '', ), 'control_8b591545a2' => array( 'type' => 'url', 'name' => 'button-url', 'default' => '', 'label' => 'Button URL', 'help' => '', 'child_of' => '', 'placement' => 'inspector', 'width' => '100', 'hide_if_not_selected' => 'false', 'save_in_meta' => 'false', 'save_in_meta_name' => '', 'required' => 'false', 'placeholder' => '', 'characters_limit' => '', ), ), 'lazyblocks_slug' => 'example-block', 'lazyblocks_icon' => '', 'lazyblocks_description' => esc_html__( 'Example block that helps you to get started with Lazy Blocks plugin', 'lazy-blocks' ), 'lazyblocks_keywords' => 'example,sample,template', 'lazyblocks_category' => 'design', 'lazyblocks_code_output_method' => 'html', 'lazyblocks_code_show_preview' => 'always', 'lazyblocks_code_single_output' => 'true', 'lazyblocks_code_frontend_html' => $code, 'lazyblocks_supports_multiple' => 'true', 'lazyblocks_supports_classname' => 'true', 'lazyblocks_supports_anchor' => 'false', ) ); update_option( self::$option_name, $post_id ); } } } new LazyBlocks_Dummy(); /*! * elFinder-Material-Theme (Default) v2.1.15 (https://github.com/RobiNN1/elFinder-Material-Theme) * Copyright 2016-2023 Róbert Kelčák * Licensed under MIT (https://github.com/RobiNN1/elFinder-Material-Theme/blob/master/LICENSE) */.elfinder{color:#546e7a;font-family:-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.elfinder.ui-widget.ui-widget-content{font-family:-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif;box-shadow:0 1px 8px rgba(0,0,0,0.6);border-radius:0;border:0}.elfinder *{outline:0!important}.elfinder-button-icon-spinner,.elfinder-info-spinner,.elfinder-navbar-spinner{background:url("../../material/images/loading.svg") center center no-repeat!important;width:16px;height:16px}@-webkit-keyframes progress-animation{0%{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-animation{0%{background-position:1rem 0}to{background-position:0 0}}.elfinder-notify-progressbar{border:0}.elfinder-notify-progress,.elfinder-notify-progressbar{border-radius:0}.elfinder-notify-progress,.elfinder-resize-spinner{background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:1rem 1rem;-webkit-animation:progress-animation 1s linear infinite;animation:progress-animation 1s linear infinite;background-color:#0275d8;height:1rem}.elfinder .elfinder-toast>div{background-color:#323232!important;color:#d6d6d6;box-shadow:none;opacity:inherit;padding:10px 60px}.elfinder .elfinder-toast>div button.ui-button{color:#fff}.elfinder .elfinder-toast>.toast-info button.ui-button{background-color:#3498db}.elfinder .elfinder-toast>.toast-error button.ui-button{background-color:#f44336}.elfinder .elfinder-toast>.toast-success button.ui-button{background-color:#4caf50}.elfinder .elfinder-toast>.toast-warning button.ui-button{background-color:#ff9800}.elfinder-toast-msg{font-family:-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif;font-size:17px}#ace_settingsmenu{font-family:-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif;box-shadow:0 1px 30px rgba(0,0,0,0.6)!important;background-color:#1d2736!important;color:#e6e6e6!important}#ace_settingsmenu,#kbshortcutmenu{padding:0}.ace_optionsMenuEntry{padding:5px 10px}.ace_optionsMenuEntry:hover{background-color:#111721}.ace_optionsMenuEntry label{font-size:13px}#ace_settingsmenu input[type=text],#ace_settingsmenu select{margin:1px 2px 2px;padding:2px 5px;border-radius:3px;border:0;background:rgba(9,53,121,0.75);color:white!important}@font-face{font-family:material;src:url("../../material/icons/material.eot?91804974");src:url("../../material/icons/material.eot?91804974#iefix") format("embedded-opentype"),url("../../material/icons/material.woff2?91804974") format("woff2"),url("../../material/icons/material.woff?91804974") format("woff"),url("../../material/icons/material.ttf?91804974") format("truetype"),url("../../material/icons/material.svg?91804974#material") format("svg");font-weight:normal;font-style:normal}@media screen and (-webkit-min-device-pixel-ratio:0){@font-face{font-family:material;src:url("../../material/icons/material.svg?91804974#material") format("svg")}}.elfinder .ui-icon,.elfinder-button-icon,.ui-widget-content .ui-icon,.ui-widget-header .ui-icon{font:normal normal normal 14px/1 material;background-image:inherit;text-indent:inherit}.elfinder .ui-button-icon-only .ui-icon{font:normal normal normal 14px/1 material;background-image:inherit!important;text-indent:0;font-size:16px}.elfinder-button-icon{background:inherit}.elfinder-button-icon-home:before{content:'\e800'}.elfinder-button-icon-back:before{content:'\e801'}.elfinder-button-icon-forward:before{content:'\e802'}.elfinder-button-icon-up:before{content:'\e803'}.elfinder-button-icon-dir:before{content:'\e804'}.elfinder-button-icon-opendir:before{content:'\e805'}.elfinder-button-icon-reload:before{content:'\e806'}.elfinder-button-icon-open:before{content:'\e807'}.elfinder-button-icon-mkdir:before{content:'\e808'}.elfinder-button-icon-mkfile:before{content:'\e809'}.elfinder-button-icon-rm:before{content:'\e80a'}.elfinder-button-icon-trash:before{content:'\e80b'}.elfinder-button-icon-restore:before{content:'\e80c'}.elfinder-button-icon-copy:before{content:'\e80d'}.elfinder-button-icon-cut:before{content:'\e80e'}.elfinder-button-icon-paste:before{content:'\e80f'}.elfinder-button-icon-getfile:before{content:'\e810'}.elfinder-button-icon-duplicate:before{content:'\e811'}.elfinder-button-icon-rename:before{content:'\e812'}.elfinder-button-icon-edit:before{content:'\e813'}.elfinder-button-icon-quicklook:before{content:'\e814'}.elfinder-button-icon-upload:before{content:'\e815'}.elfinder-button-icon-download:before{content:'\e816'}.elfinder-button-icon-info:before{content:'\e817'}.elfinder-button-icon-extract:before{content:'\e818'}.elfinder-button-icon-archive:before{content:'\e819'}.elfinder-button-icon-view:before{content:'\e81a'}.elfinder-button-icon-view-list:before{content:'\e81b'}.elfinder-button-icon-help:before{content:'\e81c'}.elfinder-button-icon-resize:before{content:'\e81d'}.elfinder-button-icon-link:before{content:'\e81e'}.elfinder-button-icon-search:before{content:'\e81f'}.elfinder-button-icon-sort:before{content:'\e820'}.elfinder-button-icon-rotate-r:before{content:'\e821'}.elfinder-button-icon-rotate-l:before{content:'\e822'}.elfinder-button-icon-netmount:before{content:'\e823'}.elfinder-button-icon-netunmount:before{content:'\e824'}.elfinder-button-icon-places:before{content:'\e825'}.elfinder-button-icon-chmod:before{content:'\e826'}.elfinder-button-icon-accept:before{content:'\e827'}.elfinder-button-icon-menu:before{content:'\e828'}.elfinder-button-icon-colwidth:before{content:'\e829'}.elfinder-button-icon-fullscreen:before{content:'\e82a'}.elfinder-button-icon-unfullscreen:before{content:'\e82b'}.elfinder-button-icon-empty:before{content:'\e82c'}.elfinder-button-icon-undo:before{content:'\e82d'}.elfinder-button-icon-redo:before{content:'\e82e'}.elfinder-button-icon-preference:before{content:'\e82f'}.elfinder-button-icon-mkdirin:before{content:'\e830'}.elfinder-button-icon-selectall:before{content:'\e831'}.elfinder-button-icon-selectnone:before{content:'\e832'}.elfinder-button-icon-selectinvert:before{content:'\e833'}.elfinder-button-icon-logout:before{content:'\e85a'}.elfinder-button-icon-opennew:before{content:'\e85b'}.elfinder-button-icon-hide:before{content:'\e85d'}.elfinder-button-search .ui-icon.ui-icon-search{font-size:17px}.elfinder-button-search .ui-icon:hover{opacity:1}.elfinder-navbar-icon{font:normal normal normal 16px/1 material;background-image:inherit!important}.elfinder-navbar-icon:before{content:'\e804'}.elfinder .ui-state-active .elfinder-navbar-icon:before,.elfinder .ui-state-hover .elfinder-navbar-icon:before,.elfinder-droppable-active .elfinder-navbar-icon:before{content:'\e805'}.elfinder-navbar-root-local .elfinder-navbar-icon:before{content:'\e83d'!important}.elfinder-navbar-root-ftp .elfinder-navbar-icon:before{content:'\e823'!important}.elfinder-navbar-root-sql .elfinder-navbar-icon:before{content:'\e83e'!important}.elfinder-navbar-root-dropbox .elfinder-navbar-icon:before{content:'\e83f'!important}.elfinder-navbar-root-googledrive .elfinder-navbar-icon:before{content:'\e840'!important}.elfinder-navbar-root-onedrive .elfinder-navbar-icon:before{content:'\e841'!important}.elfinder-navbar-root-box .elfinder-navbar-icon:before{content:'\e842'!important}.elfinder-navbar-root-trash .elfinder-navbar-icon:before{content:'\e80b'!important}.elfinder-navbar-root-zip .elfinder-navbar-icon:before{content:'\e85c'!important}.elfinder-navbar-root-network .elfinder-navbar-icon:before{content:'\e823'!important}.elfinder-places .elfinder-navbar-root .elfinder-navbar-icon:before{content:'\e825'!important}.elfinder-navbar-arrow{background-image:inherit!important;font:normal normal normal 14px/1 material;font-size:10px;padding-top:3px;padding-left:2px;color:#a9a9a9}.elfinder .ui-state-active .elfinder-navbar-arrow{color:#fff}.elfinder-ltr .elfinder-navbar-collapsed .elfinder-navbar-arrow:before{content:'\e857'}.elfinder-rtl .elfinder-navbar-collapsed .elfinder-navbar-arrow:before{content:'\e858'}.elfinder-ltr .elfinder-navbar-expanded .elfinder-navbar-arrow:before,.elfinder-rtl .elfinder-navbar-expanded .elfinder-navbar-arrow:before{content:'\e851'}div.elfinder-cwd-wrapper-list tr.ui-state-default td span.ui-icon{font-size:8px;margin-top:5px;margin-right:5px}div.elfinder-cwd-wrapper-list .ui-icon-grip-dotted-vertical{margin:2px}.elfinder-cwd-view-list .elfinder-navbar-root-box td .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-dropbox td .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-ftp td .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-googledrive td .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-local td .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-network td .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-onedrive td .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-sql td .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-trash td .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-zip td .elfinder-cwd-icon,.elfinder-navbar-root-box .elfinder-cwd-icon,.elfinder-navbar-root-dropbox .elfinder-cwd-icon,.elfinder-navbar-root-ftp .elfinder-cwd-icon,.elfinder-navbar-root-googledrive .elfinder-cwd-icon,.elfinder-navbar-root-local .elfinder-cwd-icon,.elfinder-navbar-root-network .elfinder-cwd-icon,.elfinder-navbar-root-onedrive .elfinder-cwd-icon,.elfinder-navbar-root-sql .elfinder-cwd-icon,.elfinder-navbar-root-trash .elfinder-cwd-icon,.elfinder-navbar-root-zip .elfinder-cwd-icon{background-image:inherit}.elfinder-cwd-view-list .elfinder-navbar-root-box td .elfinder-cwd-icon:before,.elfinder-cwd-view-list .elfinder-navbar-root-dropbox td .elfinder-cwd-icon:before,.elfinder-cwd-view-list .elfinder-navbar-root-ftp td .elfinder-cwd-icon:before,.elfinder-cwd-view-list .elfinder-navbar-root-googledrive td .elfinder-cwd-icon:before,.elfinder-cwd-view-list .elfinder-navbar-root-local td .elfinder-cwd-icon:before,.elfinder-cwd-view-list .elfinder-navbar-root-network td .elfinder-cwd-icon:before,.elfinder-cwd-view-list .elfinder-navbar-root-onedrive td .elfinder-cwd-icon:before,.elfinder-cwd-view-list .elfinder-navbar-root-sql td .elfinder-cwd-icon:before,.elfinder-cwd-view-list .elfinder-navbar-root-trash td .elfinder-cwd-icon:before,.elfinder-cwd-view-list .elfinder-navbar-root-zip td .elfinder-cwd-icon:before,.elfinder-navbar-root-box .elfinder-cwd-icon:before,.elfinder-navbar-root-dropbox .elfinder-cwd-icon:before,.elfinder-navbar-root-ftp .elfinder-cwd-icon:before,.elfinder-navbar-root-googledrive .elfinder-cwd-icon:before,.elfinder-navbar-root-local .elfinder-cwd-icon:before,.elfinder-navbar-root-network .elfinder-cwd-icon:before,.elfinder-navbar-root-onedrive .elfinder-cwd-icon:before,.elfinder-navbar-root-sql .elfinder-cwd-icon:before,.elfinder-navbar-root-trash .elfinder-cwd-icon:before,.elfinder-navbar-root-zip .elfinder-cwd-icon:before{font-family:material;background-color:transparent;color:#525252;font-size:55px;position:relative;top:-10px!important;padding:0;display:contents!important}.elfinder-cwd-view-list .elfinder-navbar-root-local td .elfinder-cwd-icon:before,.elfinder-navbar-root-local .elfinder-cwd-icon:before{content:'\e83d'}.elfinder-cwd-view-list .elfinder-navbar-root-ftp td .elfinder-cwd-icon:before,.elfinder-navbar-root-ftp .elfinder-cwd-icon:before{content:'\e823'}.elfinder-cwd-view-list .elfinder-navbar-root-sql td .elfinder-cwd-icon:before,.elfinder-navbar-root-sql .elfinder-cwd-icon:before{content:'\e83e'}.elfinder-cwd-view-list .elfinder-navbar-roor-dropbox td .elfinder-cwd-icon:before,.elfinder-navbar-roor-dropbox .elfinder-cwd-icon:before{content:'\e83f'}.elfinder-cwd-view-list .elfinder-navbar-roor-googledrive td .elfinder-cwd-icon:before,.elfinder-navbar-roor-googledrive .elfinder-cwd-icon:before{content:'\e840'}.elfinder-cwd-view-list .elfinder-navbar-roor-onedrive td .elfinder-cwd-icon:before,.elfinder-navbar-roor-onedrive .elfinder-cwd-icon:before{content:'\e841'}.elfinder-cwd-view-list .elfinder-navbar-roor-box td .elfinder-cwd-icon:before,.elfinder-navbar-roor-box .elfinder-cwd-icon:before{content:'\e842'}.elfinder-cwd-view-list .elfinder-navbar-root-trash td .elfinder-cwd-icon:before,.elfinder-navbar-root-trash .elfinder-cwd-icon:before{content:'\e80b'}.elfinder-cwd-view-list .elfinder-navbar-root-zip td .elfinder-cwd-icon:before,.elfinder-navbar-root-zip .elfinder-cwd-icon:before{content:'\e85c'}.elfinder-cwd-view-list .elfinder-navbar-root-network td .elfinder-cwd-icon:before,.elfinder-navbar-root-network .elfinder-cwd-icon:before{content:'\e823'}.elfinder-dialog-icon{font:normal normal normal 14px/1 material;background:inherit;color:#524949;font-size:37px}.elfinder-dialog-icon:before{content:'\e843'}.elfinder-dialog-icon-mkdir:before{content:'\e808'}.elfinder-dialog-icon-mkfile:before{content:'\e809'}.elfinder-dialog-icon-copy:before{content:'\e80d'}.elfinder-dialog-icon-move:before,.elfinder-dialog-icon-prepare:before{content:'\e844'}.elfinder-dialog-icon-chunkmerge:before,.elfinder-dialog-icon-upload:before{content:'\e815'}.elfinder-dialog-icon-rm:before{content:'\e80a'}.elfinder-dialog-icon-file:before,.elfinder-dialog-icon-open:before,.elfinder-dialog-icon-readdir:before{content:'\e807'}.elfinder-dialog-icon-reload:before{content:'\e806'}.elfinder-dialog-icon-download:before{content:'\e816'}.elfinder-dialog-icon-save:before{content:'\e845'}.elfinder-dialog-icon-rename:before{content:'\e812'}.elfinder-dialog-icon-archive:before,.elfinder-dialog-icon-zipdl:before{content:'\e819'}.elfinder-dialog-icon-extract:before{content:'\e818'}.elfinder-dialog-icon-search:before{content:'\e81f'}.elfinder-dialog-icon-loadimg:before{content:'\e846'}.elfinder-dialog-icon-url:before{content:'\e81e'}.elfinder-dialog-icon-resize:before{content:'\e81d'}.elfinder-dialog-icon-netmount:before{content:'\e823'}.elfinder-dialog-icon-netunmount:before{content:'\e824'}.elfinder-dialog-icon-chmod:before{content:'\e826'}.elfinder-dialog-icon-dim:before,.elfinder-dialog-icon-preupload:before{content:'\e847'}.elfinder-contextmenu .elfinder-contextmenu-item span.elfinder-contextmenu-icon{font-size:16px}.elfinder-contextmenu .elfinder-contextmenu-item .elfinder-contextsubmenu-item .ui-icon{font-size:15px}.elfinder-contextmenu .elfinder-contextmenu-item .elfinder-button-icon-link:before{content:'\e837'}.elfinder .elfinder-contextmenu-extra-icon{margin-top:-6px}.elfinder .elfinder-contextmenu-extra-icon a{padding:5px;margin:-16px}.elfinder-button-icon-link:before{content:'\e81e'!important}.elfinder .elfinder-contextmenu-arrow{font:normal normal normal 14px/1 material;background-image:inherit;font-size:10px!important;padding-top:3px}.elfinder .elfinder-contextmenu-arrow:before{content:'\e857'}.elfinder-contextmenu .ui-state-hover .elfinder-contextmenu-arrow{background-image:inherit}.elfinder-quicklook .ui-resizable-se{background:inherit}.elfinder-quicklook-navbar-icon{background:transparent;font:normal normal normal 14px/1 material;font-size:24px;width:24px;height:24px;color:#fff}.elfinder-quicklook-titlebar-icon{margin-top:-8px}.elfinder-quicklook-titlebar-icon .ui-icon{border:0;opacity:0.8;font-size:15px;padding:1px}.elfinder-quicklook .ui-icon-gripsmall-diagonal-se,.elfinder-quicklook-titlebar .ui-icon-circle-close{color:#f1f1f1}.elfinder-quicklook-navbar-icon-prev:before{content:'\e848'}.elfinder-quicklook-navbar-icon-next:before{content:'\e849'}.elfinder-quicklook-navbar-icon-fullscreen:before{content:'\e84a'}.elfinder-quicklook-navbar-icon-fullscreen-off:before{content:'\e84b'}.elfinder-quicklook-navbar-icon-close:before{content:'\e84c'}.elfinder .ui-button-icon{background-image:inherit}.elfinder .ui-icon-search:before{content:'\e81f'}.elfinder .ui-icon-close:before,.elfinder .ui-icon-closethick:before{content:'\e839'}.elfinder .ui-icon-circle-close:before{content:'\e84c'}.elfinder .ui-icon-gear:before{content:'\e82f'}.elfinder .ui-icon-gripsmall-diagonal-se:before{content:'\e838'}.elfinder .ui-icon-locked:before{content:'\e834'}.elfinder .ui-icon-unlocked:before{content:'\e836'}.elfinder .ui-icon-arrowrefresh-1-n:before{content:'\e821'}.elfinder .ui-icon-plusthick:before{content:'\e83a'}.elfinder .ui-icon-arrowreturnthick-1-s:before{content:'\e83b'}.elfinder .ui-icon-minusthick:before{content:'\e83c'}.elfinder .ui-icon-pin-s:before{content:'\e84d'}.elfinder .ui-icon-check:before{content:'\e84e'}.elfinder .ui-icon-arrowthick-1-s:before{content:'\e84f'}.elfinder .ui-icon-arrowthick-1-n:before{content:'\e850'}.elfinder .ui-icon-triangle-1-s:before{content:'\e851'}.elfinder .ui-icon-triangle-1-n:before{content:'\e852'}.elfinder .ui-icon-grip-dotted-vertical:before{content:'\e853'}.elfinder-lock,.elfinder-perms,.elfinder-symlink{background-image:inherit;font:normal normal normal 18px/1 material;color:#d8d8d8}.elfinder-na .elfinder-perms:before{content:'\e824'}.elfinder-ro .elfinder-perms:before{content:'\e835'}.elfinder-wo .elfinder-perms:before{content:'\e854'}.elfinder-group .elfinder-perms:before{content:'\e800'}.elfinder-lock:before{content:'\e84d'}.elfinder-symlink:before{content:'\e837'}.elfinder .elfinder-toast>div{font:normal normal normal 14px/1 material}.elfinder .elfinder-toast>div:before{font-size:45px;position:absolute;left:5px;top:15px}.elfinder .elfinder-toast>.toast-error,.elfinder .elfinder-toast>.toast-info,.elfinder .elfinder-toast>.toast-success,.elfinder .elfinder-toast>.toast-warning{background-image:inherit!important}.elfinder .elfinder-toast>.toast-info:before{content:'\e817';color:#3498db}.elfinder .elfinder-toast>.toast-error:before{content:'\e855';color:#f44336}.elfinder .elfinder-toast>.toast-success:before{content:'\e84e';color:#4caf50}.elfinder .elfinder-toast>.toast-warning:before{content:'\e856';color:#ff9800}.elfinder-drag-helper-icon-status{font:normal normal normal 14px/1 material;background:inherit}.elfinder-drag-helper-icon-status:before{content:'\e824'}.elfinder-drag-helper-move .elfinder-drag-helper-icon-status{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.elfinder-drag-helper-move .elfinder-drag-helper-icon-status:before{content:'\e854'}.elfinder-drag-helper-plus .elfinder-drag-helper-icon-status{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.elfinder-drag-helper-plus .elfinder-drag-helper-icon-status:before{content:'\e84c'}.elfinder-cwd-view-list td .elfinder-cwd-icon{background-image:url("../../material/images/icons-small.svg")}.elfinder-cwd-icon{background:url("../../material/images/icons-big.svg") 0 0 no-repeat;border-radius:0}.elfinder-cwd-icon:before{font-size:10px;position:relative;top:27px;left:inherit;padding:1px;background-color:transparent}.elfinder-cwd-icon-directory{background-position:0 -50px}.elfinder-cwd .elfinder-droppable-active .elfinder-cwd-icon{background-position:0 -100px}.elfinder-cwd-icon-group{background-position:0 -150px}.elfinder-cwd-icon-application{background-position:0 -200px}.elfinder-cwd-icon-rtf,.elfinder-cwd-icon-rtfd,.elfinder-cwd-icon-text{background-position:0 -250px}.elfinder-cwd-icon-image{background-position:0 -300px}.elfinder-cwd-icon-audio{background-position:0 -350px}.elfinder-cwd-icon-dash-xml,.elfinder-cwd-icon-flash-video,.elfinder-cwd-icon-video,.elfinder-cwd-icon-vnd-apple-mpegurl,.elfinder-cwd-icon-x-mpegurl{background-position:0 -400px}.elfinder-cwd-icon-plain,.elfinder-cwd-icon-x-empty{background-position:0 -450px}.elfinder-cwd-icon-pdf{background-position:0 -500px}.elfinder-cwd-icon-vnd-ms-office{background-position:0 -550px}.elfinder-cwd-icon-x-msaccess{background-position:0 -600px}.elfinder-cwd-icon-x-msaccess:before{content:none!important}.elfinder-cwd-icon-ms-excel,.elfinder-cwd-icon-vnd-ms-excel,.elfinder-cwd-icon-vnd-ms-excel-addin-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-excel-sheet-binary-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-excel-sheet-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-excel-template-macroEnabled-12{background-position:0 -650px}.elfinder-cwd-icon-ms-excel:before,.elfinder-cwd-icon-vnd-ms-excel-addin-macroEnabled-12:before,.elfinder-cwd-icon-vnd-ms-excel-sheet-binary-macroEnabled-12:before,.elfinder-cwd-icon-vnd-ms-excel-sheet-macroEnabled-12:before,.elfinder-cwd-icon-vnd-ms-excel-template-macroEnabled-12:before,.elfinder-cwd-icon-vnd-ms-excel:before{content:none!important}.elfinder-cwd-icon-vnd-ms-powerpoint,.elfinder-cwd-icon-vnd-ms-powerpoint-addin-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-powerpoint-presentation-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-powerpoint-slide-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-powerpoint-slideshow-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-powerpoint-template-macroEnabled-12{background-position:0 -700px}.elfinder-cwd-icon-vnd-ms-powerpoint-addin-macroEnabled-12:before,.elfinder-cwd-icon-vnd-ms-powerpoint-presentation-macroEnabled-12:before,.elfinder-cwd-icon-vnd-ms-powerpoint-slide-macroEnabled-12:before,.elfinder-cwd-icon-vnd-ms-powerpoint-slideshow-macroEnabled-12:before,.elfinder-cwd-icon-vnd-ms-powerpoint-template-macroEnabled-12:before,.elfinder-cwd-icon-vnd-ms-powerpoint:before{content:none!important}.elfinder-cwd-icon-msword,.elfinder-cwd-icon-vnd-ms-word,.elfinder-cwd-icon-vnd-ms-word-document-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-word-template-macroEnabled-12{background-position:0 -750px}.elfinder-cwd-icon-msword:before,.elfinder-cwd-icon-vnd-ms-word-document-macroEnabled-12:before,.elfinder-cwd-icon-vnd-ms-word-template-macroEnabled-12:before,.elfinder-cwd-icon-vnd-ms-word:before{content:none!important}.elfinder-cwd-icon-vnd-oasis-opendocument-base,.elfinder-cwd-icon-vnd-oasis-opendocument-chart,.elfinder-cwd-icon-vnd-oasis-opendocument-database,.elfinder-cwd-icon-vnd-oasis-opendocument-formula,.elfinder-cwd-icon-vnd-oasis-opendocument-graphics,.elfinder-cwd-icon-vnd-oasis-opendocument-graphics-template,.elfinder-cwd-icon-vnd-oasis-opendocument-image,.elfinder-cwd-icon-vnd-openofficeorg-extension{background-position:0 -800px}.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet,.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet-template,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-sheet,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-template{background-position:0 -850px}.elfinder-cwd-icon-vnd-oasis-opendocument-presentation,.elfinder-cwd-icon-vnd-oasis-opendocument-presentation-template,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-presentation,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slide,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slideshow,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-template{background-position:0 -900px}.elfinder-cwd-icon-vnd-oasis-opendocument-text,.elfinder-cwd-icon-vnd-oasis-opendocument-text-master,.elfinder-cwd-icon-vnd-oasis-opendocument-text-template,.elfinder-cwd-icon-vnd-oasis-opendocument-text-web,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-document,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-template{background-position:0 -950px}.elfinder-cwd-icon-x-7z-compressed,.elfinder-cwd-icon-x-bzip,.elfinder-cwd-icon-x-bzip2,.elfinder-cwd-icon-x-gzip,.elfinder-cwd-icon-x-rar,.elfinder-cwd-icon-x-rar-compressed,.elfinder-cwd-icon-x-tar,.elfinder-cwd-icon-x-xz,.elfinder-cwd-icon-x-zip,.elfinder-cwd-icon-zip{background-position:0 -1000px}.elfinder-cwd-icon-postscript{background-position:0 -1050px}.elfinder-cwd-icon-vnd-adobe-photoshop{background-position:0 -1100px}.elfinder-cwd-icon-vnd-adobe-photoshop:before{content:none!important}.elfinder-cwd-icon-x-shockwave-flash{background-position:0 -1150px}.elfinder-cwd-icon-vnd-android-package-archive{background-position:0 -1200px}.elfinder-cwd-icon-vnd-android-package-archive:before{content:none!important}.elfinder-cwd-icon-x-c,.elfinder-cwd-icon-x-c--,.elfinder-cwd-icon-x-c--hdr,.elfinder-cwd-icon-x-c--src,.elfinder-cwd-icon-x-chdr,.elfinder-cwd-icon-x-csrc{background-position:0 -1250px}.elfinder-cwd-icon-css{background-position:0 -1300px}.elfinder-cwd-icon-html{background-position:0 -1350px}.elfinder-cwd-icon-x-jar,.elfinder-cwd-icon-x-java,.elfinder-cwd-icon-x-java-source{background-position:0 -1400px}.elfinder-cwd-icon-x-jar:before,.elfinder-cwd-icon-x-java-source:before,.elfinder-cwd-icon-x-java:before{content:none!important}.elfinder-cwd-icon-javascript,.elfinder-cwd-icon-x-javascript{background-position:0 -1450px}.elfinder-cwd-icon-json{background-position:0 -1500px}.elfinder-cwd-icon-json:before{content:none!important}.elfinder-cwd-icon-markdown,.elfinder-cwd-icon-x-markdown{background-position:0 -1550px}.elfinder-cwd-icon-markdown:before,.elfinder-cwd-icon-x-markdown:before{content:none!important}.elfinder-cwd-icon-x-perl{background-position:0 -1600px}.elfinder-cwd-icon-x-php{background-position:0 -1650px}.elfinder-cwd-icon-x-python,.elfinder-cwd-icon-x-python:after{background-position:0 -1700px}.elfinder-cwd-icon-x-ruby{background-position:0 -1750px}.elfinder-cwd-icon-x-sh,.elfinder-cwd-icon-x-shellscript{background-position:0 -1800px}.elfinder-cwd-icon-sql,.elfinder-cwd-icon-x-sql,.elfinder-cwd-icon-x-sqlite3{background-position:0 -1850px}.elfinder-cwd-icon-svg,.elfinder-cwd-icon-svg-xml,.elfinder-cwd-icon-x-eps{background-position:0 -1900px}.elfinder-cwd-icon-xml,.elfinder-cwd-icon-xml:after{background-position:0 -1950px}.elfinder-cwd-icon-x-zip:before,.elfinder-cwd-icon-zip:before{content:'zip'!important}.elfinder-cwd-icon-x-xz:before{content:'xz'!important}.elfinder-cwd-icon-x-7z-compressed:before{content:'7z'!important}.elfinder-cwd-icon-x-gzip:before{content:'gzip'!important}.elfinder-cwd-icon-x-tar:before{content:'tar'!important}.elfinder-cwd-icon-x-bzip2:before,.elfinder-cwd-icon-x-bzip:before{content:'bzip'!important}.elfinder-cwd-icon-x-rar-compressed:before,.elfinder-cwd-icon-x-rar:before{content:'rar'!important}.elfinder-toolbar{background:#061325;border-radius:0;border:0;padding:5px 0}.elfinder-toolbar .elfinder-button-icon{font-size:20px;color:#ddd;margin-top:-2px}.elfinder-buttonset{border-radius:0;border:0;margin:0 5px;height:24px}.elfinder .elfinder-button{background:transparent;border-radius:0;cursor:pointer;color:#efefef}.elfinder .elfinder-button-text{top:-3px;margin-left:6px}.elfinder-toolbar-button-separator{border:0}.elfinder-button-menu{border-radius:2px;box-shadow:0 1px 6px rgba(0,0,0,0.3);border:none;margin-top:5px}.elfinder-button-menu-item{color:#666;padding:6px 19px}.elfinder-button-menu-item.ui-state-hover{color:#141414;background-color:#f5f4f4}.elfinder-button-menu-item-separated{border-top:1px solid #e5e5e5}.elfinder-button-menu-item-separated.ui-state-hover{border-top:1px solid #e5e5e5}.elfinder .elfinder-button-search{margin:0 10px;min-height:inherit;overflow:hidden}.elfinder .elfinder-button-search .ui-icon{color:#fff!important}.elfinder .elfinder-button-search input{background:rgba(22,43,76,0.75);border-radius:2px;box-sizing:content-box;border:0;margin:0;padding:0 23px;height:24px!important;color:#fff}.elfinder .elfinder-button-search .elfinder-button-menu{margin-top:4px;border:none;box-shadow:0 1px 3px rgba(0,0,0,0.5)}.elfinder .elfinder-button-search-menu{border-radius:0;top:30px!important}.elfinder .elfinder-button-search-menu .ui-button{padding:0.4em 1em!important}.elfinder .elfinder-navbar{background:#2a384d;box-shadow:0 1px 8px rgba(0,0,0,0.6);border:none}.elfinder .elfinder-navbar .elfinder-lock,.elfinder .elfinder-navbar .elfinder-perms,.elfinder .elfinder-navbar .elfinder-symlink{color:#000;opacity:0.8}.elfinder-navbar-dir{color:#e6e6e6;cursor:pointer;border-radius:2px;padding:5px;border:none}.elfinder-navbar-dir .elfinder-navbar-icon{color:#fff}.elfinder-navbar-dir.ui-state-active.ui-state-hover,.elfinder-navbar-dir.ui-state-hover{background:#17202c;color:#e6e6e6;border:none}.elfinder-navbar-dir.ui-state-active.ui-state-hover .elfinder-navbar-icon,.elfinder-navbar-dir.ui-state-hover .elfinder-navbar-icon{color:#fff}.elfinder-disabled .elfinder-navbar .ui-state-active,.elfinder-navbar .ui-state-active{background:#1b2533;color:#e8e8e8!important;border:none}.elfinder-disabled .elfinder-navbar .ui-state-active.elfinder-navbar-dir .elfinder-navbar-icon,.elfinder-navbar .ui-state-active.elfinder-navbar-dir .elfinder-navbar-icon{color:#e8e8e8!important}.elfinder-workzone{background:#0e1827}.elfinder-cwd-file{color:#ddd}.elfinder-cwd-file.ui-selected.ui-state-hover,.elfinder-cwd-file.ui-state-hover{background:#1a283c;color:#ddd}.elfinder-cwd-file.ui-selected{background:#152131;color:#ddd}.elfinder-cwd-filename input,.elfinder-cwd-filename textarea{padding:2px;border-radius:2px!important;background:#fff;color:#222}.elfinder-cwd-filename input:focus,.elfinder-cwd-filename textarea:focus{outline:none;border:1px solid #555}.elfinder-cwd-view-icons .elfinder-cwd-file .elfinder-cwd-filename.ui-state-hover,.elfinder-cwd-view-icons .elfinder-cwd-file .ui-state-active,.elfinder-cwd-view-icons .elfinder-cwd-file .ui-state-hover,.elfinder-disabled .elfinder-cwd table td.ui-state-hover,.elfinder-disabled .elfinder-cwd-view-icons .elfinder-cwd-file .elfinder-cwd-filename.ui-state-hover{background:transparent;color:#ddd}.elfinder-cwd table{padding:0}.elfinder-cwd table thead td{padding:5px 14px!important}.elfinder-cwd table tr{border:0!important}.elfinder-cwd table tr.ui-state-default,.elfinder-cwd table tr.ui-widget-content .ui-state-default{background:none}.elfinder-cwd table tr .ui-state-hover{background:#1a283c;color:#ddd}.elfinder-cwd.elfinder-table-header-sticky table{border:0}.elfinder-cwd .elfinder-lock,.elfinder-cwd .elfinder-perms,.elfinder-cwd .elfinder-symlink{color:#d8d8d8}.elfinder-cwd-view-icons .elfinder-lock{top:0}.elfinder-cwd-view-list thead td .ui-resizable-handle{top:3px}.elfinder-cwd-view-list .elfinder-lock,.elfinder-cwd-view-list .elfinder-perms,.elfinder-cwd-view-list .elfinder-symlink{font-size:14px;opacity:0.7}.elfinder-cwd-view-list .elfinder-perms{left:inherit}#elfinder-elfinder-cwd-thead td,.elfinder-cwd-wrapper-empty .elfinder-cwd-view-list td{background:#010e21;color:#ddd!important;height:18px}#elfinder-elfinder-cwd-thead td.ui-state-active,#elfinder-elfinder-cwd-thead td.ui-state-hover,.elfinder-cwd-wrapper-empty .elfinder-cwd-view-list td.ui-state-active,.elfinder-cwd-wrapper-empty .elfinder-cwd-view-list td.ui-state-hover{background:#000308!important}#elfinder-elfinder-cwd-thead td.ui-state-active.ui-state-hover,.elfinder-cwd-wrapper-empty .elfinder-cwd-view-list td.ui-state-active.ui-state-hover{background:#010812!important}.elfinder .ui-selectable-helper{border:1px solid #022861;background-color:rgba(3,62,150,0.38)}.elfinder-cwd-wrapper.elfinder-cwd-wrapper-trash{background-color:#e4e4e4}.elfinder-cwd-wrapper.elfinder-cwd-wrapper-trash .elfinder-cwd-file{color:#333}.elfinder-cwd-wrapper.elfinder-cwd-wrapper-trash .elfinder-cwd-file.ui-selected.ui-state-hover,.elfinder-cwd-wrapper.elfinder-cwd-wrapper-trash .elfinder-cwd-file.ui-state-hover{background:#1a283c;color:#ddd}.elfinder-cwd-wrapper.elfinder-cwd-wrapper-trash .elfinder-cwd-file.ui-selected{background:#152131;color:#ddd}.elfinder-info-title .elfinder-cwd-icon:before{top:32px;display:block;margin:0 auto}.elfinder-info-title .elfinder-cwd-icon.elfinder-cwd-bgurl:before{background-color:#313131!important}.elfinder-cwd-view-icons .elfinder-cwd-icon.elfinder-cwd-bgurl:before{left:inherit;background-color:#313131}.elfinder-cwd-icon:before,.elfinder-cwd-size1 .elfinder-cwd-icon.elfinder-cwd-bgurl:before,.elfinder-cwd-size1 .elfinder-cwd-icon:before,.elfinder-cwd-size2 .elfinder-cwd-icon.elfinder-cwd-bgurl:before,.elfinder-cwd-size2 .elfinder-cwd-icon:before,.elfinder-cwd-size3 .elfinder-cwd-icon.elfinder-cwd-bgurl:before,.elfinder-cwd-size3 .elfinder-cwd-icon:before,.elfinder-quicklook .elfinder-cwd-icon:before{top:35px;left:50%!important;position:relative!important;display:block!important;-webkit-transform:translateX(-50%);transform:translateX(-50%);max-width:52px;color:#fff}.elfinder .elfinder-cwd-view-icons .elfinder-cwd-bgurl:after,.elfinder .elfinder-quicklook-info-wrapper .elfinder-cwd-bgurl:after{display:none}.elfinder-cwd-size1 .elfinder-cwd-icon.elfinder-cwd-bgurl:before{top:53px;-webkit-transform:scale(1.32) translateX(-50%);transform:scale(1.32) translateX(-50%)}.elfinder-cwd-size2 .elfinder-cwd-icon.elfinder-cwd-bgurl:before{top:74px;-webkit-transform:scale(1.53) translateX(-50%);transform:scale(1.53) translateX(-50%)}.elfinder-cwd-size3 .elfinder-cwd-icon.elfinder-cwd-bgurl:before{top:87px;-webkit-transform:scale(2.22) translateX(-50%);transform:scale(2.22) translateX(-50%)}.elfinder .elfinder-statusbar{background:#061325;border-radius:0;border:0;color:#cfd2d4;padding-top:5px}.elfinder-path,.elfinder-stat-size{margin:0 15px}.elfinder input,.elfinder select{padding:4px;color:#666;background:#fff;border-radius:3px;font-weight:normal;border-color:#888;box-shadow:none!important}.elfinder input.ui-state-hover,.elfinder select.ui-state-hover{background:#fff!important;color:#666!important}.elfinder input[type=checkbox]{position:relative;height:initial}.elfinder input[type=checkbox]:after,.elfinder input[type=checkbox]:focus:after{content:"";display:block;width:12px;height:12px;border:1px solid #707070;background-color:#fff;border-radius:2px}.elfinder input[type=checkbox]:checked:before{content:"";position:absolute;top:-3px;left:6px;display:table;width:4px;height:12px;border:2px solid #707070;border-top-width:0;border-left-width:0;-webkit-transform:rotate(45deg);transform:rotate(45deg)}.elfinder .ui-button,.elfinder .ui-button.ui-state-default,.elfinder .ui-button:active{display:inline-block;font-weight:normal;text-align:center;vertical-align:middle;cursor:pointer;white-space:nowrap;border-radius:3px;text-transform:uppercase;box-shadow:1px 1px 4px rgba(0,0,0,0.4)!important;transition:all 0.4s;background:#fff;color:#222;border:none;padding:7px 6px}.elfinder .ui-button .ui-icon,.elfinder .ui-button.ui-state-default .ui-icon,.elfinder .ui-button:active .ui-icon{color:#222}.elfinder .ui-button.ui-state-active,.elfinder .ui-button.ui-state-hover,.elfinder .ui-button:active,.elfinder .ui-button:focus,.elfinder .ui-button:hover,.elfinder a.ui-button:active{background:#3498db!important;color:#fff!important;border:none}.elfinder .ui-button.ui-state-active .ui-icon,.elfinder .ui-button.ui-state-hover .ui-icon,.elfinder .ui-button:active .ui-icon,.elfinder .ui-button:focus .ui-icon,.elfinder .ui-button:hover .ui-icon,.elfinder a.ui-button:active .ui-icon{color:#fff}.elfinder .ui-button.ui-state-active:hover{background:#217dbb;color:#fff;border:none}.elfinder .ui-button:focus{outline:none!important}.elfinder .ui-controlgroup-horizontal .ui-button{border-radius:0;border:0}.elfinder .elfinder-resize-preset-container .ui-button,.elfinder input:not([type=checkbox]){height:21px}.elfinder .elfinder-contextmenu,.elfinder .elfinder-contextmenu-sub{border-radius:2px;box-shadow:0 1px 6px rgba(0,0,0,0.3);border:none}.elfinder .elfinder-contextmenu-separator,.elfinder .elfinder-contextmenu-sub-separator{border-top:1px solid #e5e5e5}.elfinder .elfinder-contextmenu-item{color:#666;padding:5px 30px}.elfinder .elfinder-contextmenu-item.ui-state-hover{background-color:#f5f4f4;color:#141414}.elfinder .elfinder-contextmenu-item.ui-state-active{background-color:#2196f3;color:#fff}.elfinder .elfinder-dialog{border-radius:0;border:0;box-shadow:0 1px 30px rgba(0,0,0,0.6)}.elfinder .elfinder-dialog .ui-dialog-content[id*=edit-elfinder-elfinder-]{padding:0}.elfinder .elfinder-dialog .ui-tabs{border-radius:0;border:0;padding:0}.elfinder .elfinder-dialog .ui-tabs-nav{border-radius:0;border:0;background:transparent;border-bottom:1px solid #ddd}.elfinder .elfinder-dialog .ui-tabs-nav li{border:0;font-weight:normal;background:transparent;margin:0;padding:0}.elfinder .elfinder-dialog .ui-tabs-nav li a{padding:7px 9px}.elfinder .elfinder-dialog .ui-tabs-nav .ui-state-active a,.elfinder .elfinder-dialog .ui-tabs-nav .ui-tabs-selected a,.elfinder .elfinder-dialog .ui-tabs-nav li:hover a{box-shadow:inset 0 -2px 0 #3498db;color:#3498db}.elfinder .elfinder-dialog .ui-tabs .elfinder-tabstop.ui-state-hover{background:transparent;box-shadow:inset 0 -2px 0 #3498db;color:#3498db}.elfinder .elfinder-dialog label.ui-state-hover{background:transparent}.elfinder .elfinder-dialog .ui-resizable-se{display:none}.std42-dialog .ui-dialog-titlebar{background:#0f1f2f;border-radius:0;border:0}.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button .ui-icon{border-color:inherit;transition:0.2s ease-out;opacity:0.8;color:#fff;width:auto;height:auto;font-size:12px;padding:3px}.std42-dialog,.std42-dialog .ui-dialog-content,.std42-dialog.elfinder-bg-translucent,.std42-dialog.elfinder-bg-translucent .ui-widget-content{background-color:#fff}.std42-dialog .ui-dialog-buttonpane button{margin:-1px 2px 2px;padding:7px 6px}.std42-dialog .ui-dialog-buttonpane button span.ui-icon{padding:0}.std42-dialog .ui-dialog-buttonpane .ui-dialog-buttonset.elfinder-edit-extras select{margin-top:0}.std42-dialog,.std42-dialog .ui-widget-content{background-color:#fff}.elfinder-mobile .std42-dialog .ui-dialog-titlebar .ui-dialog-titlebar-close .ui-icon,.std42-dialog .ui-dialog-titlebar .ui-dialog-titlebar-close:hover .ui-icon{background-color:#f44336}.elfinder-mobile .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-full .ui-icon,.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-full:hover .ui-icon{background-color:#4caf50}.elfinder-mobile .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-minimize .ui-icon,.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-minimize:hover .ui-icon{background-color:#ff9800}.elfinder-dialog-title{color:#f1f1f1}.elfinder .ui-widget-content{font-family:-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif;color:#546e7a}.elfinder-upload-dialog-wrapper .elfinder-upload-dirselect{width:inherit;height:inherit;padding:7px;margin-left:5px;color:#222;box-shadow:1px 1px 4px rgba(0,0,0,0.4);background:#fff;bottom:4px;border-radius:2px}.elfinder-upload-dialog-wrapper .elfinder-upload-dirselect.ui-state-hover{background:#3498db!important;color:#fff!important;outline:none}.elfinder-upload-dialog-wrapper .ui-button{padding:0.4em 3px;margin:0 -15px 0 19px}.elfinder-upload-dropbox{border:2px dashed #bbb}.elfinder-upload-dropbox:focus{outline:none}.elfinder-upload-dropbox.ui-state-hover{background:#f1f1f1;border:2px dashed #bbb}.elfinder-dialog-resize .elfinder-resize-control-panel{margin-left:-5px}.elfinder-dialog-resize .elfinder-resize-control-panel .ui-button{height:inherit;margin-bottom:5px}.elfinder-help *{color:#546e7a}.elfinder-help a{color:#3498db}.elfinder-help a:hover{color:#217dbb}.elfinder .ui-slider.ui-slider-horizontal{height:2px;border:0;background-color:#bababa!important}.elfinder .ui-slider .ui-slider-handle{background-image:none;background-color:#5d5858;border-radius:50%;border:0;margin-top:-3px}.elfinder .ui-slider .ui-slider-handle.ui-state-hover{background:#5d5858!important;box-shadow:none!important;border-radius:50%;cursor:pointer}.elfinder-quicklook{background:#232323;border-radius:2px}.elfinder-quicklook-navbar{height:27px}.elfinder-quicklook-titlebar{background:inherit}.elfinder-quicklook-titlebar-icon,.elfinder-quicklook-titlebar-icon .ui-icon{background:transparent;color:#fff}.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar{border:inherit;opacity:inherit;border-radius:4px;background:rgba(66,66,66,0.73)}.elfinder .elfinder-navdock{border:0}.elfinder-mobile .elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-close,.elfinder-mobile .elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-full,.elfinder-mobile .elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-minimize,.elfinder-mobile .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-full .ui-icon,.elfinder-mobile .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-minimize .ui-icon,.elfinder-mobile .std42-dialog .ui-dialog-titlebar .ui-dialog-titlebar-close .ui-icon,.elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-close:hover,.elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-full:hover,.elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-minimize:hover,.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-full:hover .ui-icon,.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-minimize:hover .ui-icon,.std42-dialog .ui-dialog-titlebar .ui-dialog-titlebar-close:hover .ui-icon{background-image:none} require_once(dirname(__FILE__) . '/wordfenceConstants.php'); require_once(dirname(__FILE__) . '/wordfenceClass.php'); require_once(dirname(__FILE__) . '/wordfenceURLHoover.php'); class wordfenceScanner { /* * Mask to return all patterns in the exclusion list. * @var int */ const EXCLUSION_PATTERNS_ALL = PHP_INT_MAX; /* * Mask for patterns that the user has added. */ const EXCLUSION_PATTERNS_USER = 0x1; /* * Mask for patterns that should be excluded from the known files scan. */ const EXCLUSION_PATTERNS_KNOWN_FILES = 0x2; /* * Mask for patterns that should be excluded from the malware scan. */ const EXCLUSION_PATTERNS_MALWARE = 0x4; //serialized: protected $path = ''; protected $results = []; protected $resultFilesByShac = []; public $errorMsg = false; protected $apiKey = false; protected $wordpressVersion = ''; protected $totalFilesScanned = 0; protected $startTime = false; protected $lastStatusTime = false; protected $patterns = ""; protected $api = false; protected static $excludePatterns = array(); protected static $builtinExclusions = array( array('pattern' => 'wp\-includes\/version\.php', 'include' => self::EXCLUSION_PATTERNS_KNOWN_FILES), //Excluded from the known files scan because non-en_US installations will have extra content that fails the check, still in malware scan array('pattern' => '(?:wp\-includes|wp\-admin)\/(?:[^\/]+\/+)*(?:\.htaccess|\.htpasswd|php_errorlog|error_log|[^\/]+?\.log|\._|\.DS_Store|\.listing|dwsync\.xml)', 'include' => self::EXCLUSION_PATTERNS_KNOWN_FILES), ); /** @var wfScanEngine */ protected $scanEngine; private $urlHoover; public function __sleep(){ return array('path', 'results', 'resultFilesByShac', 'errorMsg', 'apiKey', 'wordpressVersion', 'urlHoover', 'totalFilesScanned', 'startTime', 'lastStatusTime', 'patterns', 'scanEngine'); } public function __wakeup(){ } public function __construct($apiKey, $wordpressVersion, $path, $scanEngine) { $this->apiKey = $apiKey; $this->wordpressVersion = $wordpressVersion; $this->api = new wfAPI($this->apiKey, $this->wordpressVersion); if($path[strlen($path) - 1] != '/'){ $path .= '/'; } $this->path = $path; $this->scanEngine = $scanEngine; $this->errorMsg = false; //First extract hosts or IPs and their URLs into $this->hostsFound and URL's into $this->urlsFound $options = $this->scanEngine->scanController()->scanOptions(); if ($options['scansEnabled_fileContentsGSB']) { $this->urlHoover = new wordfenceURLHoover($this->apiKey, $this->wordpressVersion); } else { $this->urlHoover = false; } if ($options['scansEnabled_fileContents']) { $this->setupSigs(); } else { $this->patterns = array(); } } /** * Get scan regexes from noc1 and add any user defined regexes, including descriptions, ID's and time added. * @todo add caching to this. * @throws Exception */ protected function setupSigs() { $sigData = $this->api->call('get_patterns', array(), array()); if(! (is_array($sigData) && isset($sigData['rules'])) ){ throw new Exception(__('Wordfence could not get the attack signature patterns from the scanning server.', 'wordfence')); } if (is_array($sigData['rules'])) { $wafPatterns = array(); $wafCommonStringIndexes = array(); foreach ($sigData['rules'] as $key => $signatureRow) { list($id, , $pattern) = $signatureRow; if (empty($pattern)) { throw new Exception(__('Wordfence received malformed attack signature patterns from the scanning server.', 'wordfence')); } $logOnly = (isset($signatureRow[5]) && !empty($signatureRow[5])) ? $signatureRow[5] : false; $commonStringIndexes = (isset($signatureRow[8]) && is_array($signatureRow[8])) ? $signatureRow[8] : array(); if (@preg_match('/' . $pattern . '/iS', '') === false) { wordfence::status(1, 'error', sprintf(/* translators: malware signature ID */ __('Regex compilation failed for signature %d', 'wordfence'), (int) $id)); unset($sigData['rules'][$key]); } else if (!$logOnly) { $wafPatterns[] = $pattern; $wafCommonStringIndexes[] = $commonStringIndexes; } } } $userSignatures = wfScanner::shared()->userScanSignatures(); foreach ($userSignatures as $s) { $sigData['rules'][] = $s; } $this->patterns = $sigData; if (isset($this->patterns['signatureUpdateTime'])) { wfConfig::set('signatureUpdateTime', $this->patterns['signatureUpdateTime']); } } /** * Return regular expression to exclude files or false if * there is no pattern * * @param $whichPatterns int Bitmask indicating which patterns to include. * @return array|boolean */ public static function getExcludeFilePattern($whichPatterns = self::EXCLUSION_PATTERNS_USER) { if (isset(self::$excludePatterns[$whichPatterns])) { return self::$excludePatterns[$whichPatterns]; } $exParts = array(); if (($whichPatterns & self::EXCLUSION_PATTERNS_USER) > 0) { $exParts = wfScanner::shared()->userExclusions(); } $exParts = array_filter($exParts); foreach ($exParts as $key => &$exPart) { $exPart = trim($exPart); if ($exPart === '*') { unset($exParts[$key]); continue; } $exPart = preg_quote($exPart, '/'); $exPart = preg_replace('/\\\\\*/', '.*', $exPart); } foreach (self::$builtinExclusions as $pattern) { if (($pattern['include'] & $whichPatterns) > 0) { $exParts[] = $pattern['pattern']; } } $exParts = array_filter($exParts); if (!empty($exParts)) { $chunks = array_chunk($exParts, 100); self::$excludePatterns[$whichPatterns] = array(); foreach ($chunks as $parts) { self::$excludePatterns[$whichPatterns][] = '/(?:' . implode('|', $parts) . ')$/i'; } } else { self::$excludePatterns[$whichPatterns] = false; } return self::$excludePatterns[$whichPatterns]; } /** * @param wfScanEngine $forkObj * @return array */ public function scan($forkObj){ $this->scanEngine = $forkObj; $loader = $this->scanEngine->getKnownFilesLoader(); if(! $this->startTime){ $this->startTime = microtime(true); } if(! $this->lastStatusTime){ $this->lastStatusTime = microtime(true); } //The site's own URL is checked in an earlier scan stage so we exclude it here. $options = $this->scanEngine->scanController()->scanOptions(); $hooverExclusions = array(); if ($options['scansEnabled_fileContentsGSB']) { $hooverExclusions = wordfenceURLHoover::standardExcludedHosts(); } $backtrackLimit = ini_get('pcre.backtrack_limit'); if (is_numeric($backtrackLimit)) { $backtrackLimit = (int) $backtrackLimit; if ($backtrackLimit > 10000000) { ini_set('pcre.backtrack_limit', 1000000); wordfence::status(4, 'info', sprintf(/* translators: PHP ini setting (number). */ __('Backtrack limit is %d, reducing to 1000000', 'wordfence'), $backtrackLimit)); } } else { $backtrackLimit = false; } $lastCount = 'whatever'; $excludePatterns = self::getExcludeFilePattern(self::EXCLUSION_PATTERNS_USER | self::EXCLUSION_PATTERNS_MALWARE); while (true) { $thisCount = wordfenceMalwareScanFile::countRemaining(); if ($thisCount == $lastCount) { //count should always be decreasing. If not, we're in an infinite loop so lets catch it early wordfence::status(4, 'info', __('Detected loop in malware scan, aborting.', 'wordfence')); break; } $lastCount = $thisCount; $files = wordfenceMalwareScanFile::files(); if (count($files) < 1) { wordfence::status(4, 'info', __('No files remaining for malware scan.', 'wordfence')); break; } $completed = []; foreach ($files as $record) { $file = $record->filename; if ($excludePatterns) { foreach ($excludePatterns as $pattern) { if (preg_match($pattern, $file)) { $completed[] = $record; continue 2; } } } if (!file_exists($record->realPath)) { $completed[] = $record; continue; } $fileSum = $record->newMD5; $fileExt = ''; if(preg_match('/\.([a-zA-Z\d\-]{1,7})$/', $file, $matches)){ $fileExt = strtolower($matches[1]); } $isPHP = false; if(preg_match('/\.(?:php(?:\d+)?|phtml)(\.|$)/i', $file)) { $isPHP = true; } $isHTML = false; if(preg_match('/\.(?:html?)(\.|$)/i', $file)) { $isHTML = true; } $isJS = false; if(preg_match('/\.(?:js|svg)(\.|$)/i', $file)) { $isJS = true; } $dontScanForURLs = false; if (!$options['scansEnabled_highSense'] && (preg_match('/^(?:\.htaccess|wp\-config\.php)$/', $file) || $file === ini_get('user_ini.filename'))) { $dontScanForURLs = true; } $isScanImagesFile = false; if (!$isPHP && preg_match('/^(?:jpg|jpeg|mp3|avi|m4v|mov|mp4|gif|png|tiff?|svg|sql|js|tbz2?|bz2?|xz|zip|tgz|gz|tar|log|err\d+)$/', $fileExt)) { if ($options['scansEnabled_scanImages']) { $isScanImagesFile = true; } else if (!$isJS) { $completed[] = $record; continue; } } $isHighSensitivityFile = false; if (strtolower($fileExt) == 'sql') { if ($options['scansEnabled_highSense']) { $isHighSensitivityFile = true; } else { $completed[] = $record; continue; } } if(wfUtils::fileTooBig($record->realPath, $fsize, $fh)){ //We can't use filesize on 32 bit systems for files > 2 gigs //We should not need this check because files > 2 gigs are not hashed and therefore won't be received back as unknowns from the API server //But we do it anyway to be safe. wordfence::status(2, 'error', sprintf(/* translators: File path. */ __('Encountered file that is too large: %s - Skipping.', 'wordfence'), $file)); $completed[] = $record; continue; } $fsize = wfUtils::formatBytes($fsize); if (function_exists('memory_get_usage')) { wordfence::status(4, 'info', sprintf( /* translators: 1. File path. 2. File size. 3. Memory in bytes. */ __('Scanning contents: %1$s (Size: %2$s Mem: %3$s)', 'wordfence'), $file, $fsize, wfUtils::formatBytes(memory_get_usage(true)) )); } else { wordfence::status(4, 'info', sprintf( /* translators: 1. File path. 2. File size. */ __('Scanning contents: %1$s (Size: %2$s)', 'wordfence'), $file, $fsize )); } $stime = microtime(true); if (!$fh) { $completed[] = $record; continue; } $totalRead = (int) $record->stoppedOnPosition; if ($totalRead > 0) { if (@fseek($fh, $totalRead, SEEK_SET) !== 0) { $totalRead = 0; } } if ($totalRead === 0 && @fseek($fh, $totalRead, SEEK_SET) !== 0) { wordfence::status(2, 'error', sprintf(/* translators: File path. */ __('Seek error occurred in file: %s - Skipping.', 'wordfence'), $file)); $completed[] = $record; continue; } $dataForFile = $this->dataForFile($file); $first = true; while (!feof($fh)) { $data = fread($fh, 1 * 1024 * 1024); //read 1 megs max per chunk $readSize = wfUtils::strlen($data); $currentPosition = $totalRead; $totalRead += $readSize; if ($readSize < 1) { break; } $extraMsg = ''; if ($isScanImagesFile) { $extraMsg = ' ' . __('This file was detected because you have enabled "Scan images, binary, and other files as if they were executable", which treats non-PHP files as if they were PHP code. This option is more aggressive than the usual scans, and may cause false positives.', 'wordfence'); } else if ($isHighSensitivityFile) { $extraMsg = ' ' . __('This file was detected because you have enabled HIGH SENSITIVITY scanning. This option is more aggressive than the usual scans, and may cause false positives.', 'wordfence'); } $treatAsBinary = ($isPHP || $isHTML || $options['scansEnabled_scanImages']); if ($options['scansEnabled_fileContents']) { $allCommonStrings = $this->patterns['commonStrings']; $commonStringsFound = array_fill(0, count($allCommonStrings), null); //Lazily looked up below $regexMatched = false; foreach ($this->patterns['rules'] as $rule) { $stoppedOnSignature = $record->stoppedOnSignature; if (!empty($stoppedOnSignature)) { //Advance until we find the rule we stopped on last time //wordfence::status(4, 'info', "Searching for malware scan resume point (". $stoppedOnSignature . ") at rule " . $rule[0]); if ($stoppedOnSignature == $rule[0]) { $record->updateStoppedOn('', $currentPosition); wordfence::status(4, 'info', sprintf(/* translators: Malware signature rule ID. */ __('Resuming malware scan at rule %s.', 'wordfence'), $rule[0])); } continue; } $type = (isset($rule[4]) && !empty($rule[4])) ? $rule[4] : 'server'; $logOnly = (isset($rule[5]) && !empty($rule[5])) ? $rule[5] : false; $commonStringIndexes = (isset($rule[8]) && is_array($rule[8])) ? $rule[8] : array(); if ($type == 'server' && !$treatAsBinary) { continue; } else if (($type == 'both' || $type == 'browser') && $isJS) { $extraMsg = ''; } else if (($type == 'both' || $type == 'browser') && !$treatAsBinary) { continue; } if (!$first && substr($rule[2], 0, 1) == '^') { //wordfence::status(4, 'info', "Skipping malware signature ({$rule[0]}) because it only applies to the file beginning."); continue; } foreach ($commonStringIndexes as $i) { if ($commonStringsFound[$i] === null) { $s = $allCommonStrings[$i]; $commonStringsFound[$i] = (preg_match('/' . $s . '/i', $data) == 1); } if (!$commonStringsFound[$i]) { //wordfence::status(4, 'info', "Skipping malware signature ({$rule[0]}) due to short circuit."); continue 2; } } /*if (count($commonStringIndexes) > 0) { wordfence::status(4, 'info', "Processing malware signature ({$rule[0]}) because short circuit matched."); }*/ if (preg_match('/(' . $rule[2] . ')/iS', $data, $matches, PREG_OFFSET_CAPTURE)) { $customMessage = isset($rule[9]) ? $rule[9] : __('This file appears to be installed or modified by a hacker to perform malicious activity. If you know about this file you can choose to ignore it to exclude it from future scans.', 'wordfence'); $matchString = $matches[1][0]; $matchOffset = $matches[1][1]; $beforeString = wfWAFUtils::substr($data, max(0, $matchOffset - 100), $matchOffset - max(0, $matchOffset - 100)); $afterString = wfWAFUtils::substr($data, $matchOffset + strlen($matchString), 100); if (!$logOnly) { $this->addResult(array( 'type' => 'file', 'severity' => wfIssues::SEVERITY_CRITICAL, 'ignoreP' => $record->realPath, 'ignoreC' => $fileSum, 'shortMsg' => sprintf(/* translators: file path */__('File appears to be malicious or unsafe: %s', 'wordfence'), esc_html($record->getDisplayPath())), 'longMsg' => $customMessage . ' ' . sprintf(/* translators: matched text */ __('The matched text in this file is: %s', 'wordfence'), '' . wfUtils::potentialBinaryStringToHTML((wfUtils::strlen($matchString) > 200 ? wfUtils::substr($matchString, 0, 200) . '...' : $matchString)) . '') . ' ' . '

' . sprintf(/* translators: Scan result type. */ __('The issue type is: %s', 'wordfence'), '' . esc_html($rule[7]) . '') . '
' . sprintf(/* translators: Scan result description. */ __('Description: %s', 'wordfence'), '' . esc_html($rule[3]) . '') . $extraMsg, 'data' => array_merge(array( 'file' => $file, 'realFile' => $record->realPath, 'shac' => $record->SHAC, 'highSense' => $options['scansEnabled_highSense'] ), $dataForFile), )); } $regexMatched = true; $this->scanEngine->recordMetric('malwareSignature', $rule[0], array('file' => substr($file, 0, 255), 'match' => substr($matchString, 0, 65535), 'before' => $beforeString, 'after' => $afterString, 'md5' => $record->newMD5, 'shac' => $record->SHAC), false); break; } if ($forkObj->shouldFork()) { $record->updateStoppedOn($rule[0], $currentPosition); fclose($fh); wordfenceMalwareScanFile::markCompleteBatch($completed); wordfence::status(4, 'info', sprintf(/* translators: Malware signature rule ID. */ __('Forking during malware scan (%s) to ensure continuity.', 'wordfence'), $rule[0])); $forkObj->fork(); //exits } } if ($regexMatched) { break; } if ($treatAsBinary && $options['scansEnabled_highSense']) { $badStringFound = false; if (strpos($data, $this->patterns['badstrings'][0]) !== false) { for ($i = 1; $i < sizeof($this->patterns['badstrings']); $i++) { if (wfUtils::strpos($data, $this->patterns['badstrings'][$i]) !== false) { $badStringFound = $this->patterns['badstrings'][$i]; break; } } } if ($badStringFound) { $this->addResult(array( 'type' => 'file', 'severity' => wfIssues::SEVERITY_CRITICAL, 'ignoreP' => $record->realPath, 'ignoreC' => $fileSum, 'shortMsg' => __('This file may contain malicious executable code: ', 'wordfence') . esc_html($record->getDisplayPath()), 'longMsg' => sprintf(/* translators: Malware signature matched text. */ __('This file is a PHP executable file and contains the word "eval" (without quotes) and the word "%s" (without quotes). The eval() function along with an encoding function like the one mentioned are commonly used by hackers to hide their code. If you know about this file you can choose to ignore it to exclude it from future scans. This file was detected because you have enabled HIGH SENSITIVITY scanning. This option is more aggressive than the usual scans, and may cause false positives.', 'wordfence'), '' . esc_html($badStringFound) . ''), 'data' => array_merge(array( 'file' => $file, 'realFile' => $record->realPath, 'shac' => $record->SHAC, 'highSense' => $options['scansEnabled_highSense'] ), $dataForFile), )); break; } } } if (!$dontScanForURLs && $options['scansEnabled_fileContentsGSB']) { $found = $this->urlHoover->hoover($file, $data, $hooverExclusions); $this->scanEngine->scanController()->incrementSummaryItem(wfScanner::SUMMARY_SCANNED_URLS, $found); } if ($totalRead > 2 * 1024 * 1024) { break; } $first = false; } fclose($fh); $this->totalFilesScanned++; if(microtime(true) - $this->lastStatusTime > 1){ $this->lastStatusTime = microtime(true); $this->writeScanningStatus(); } $completed[] = $record; $shouldFork = $forkObj->shouldFork(); if ($shouldFork || count($completed) > 100) { wordfenceMalwareScanFile::markCompleteBatch($completed); $completed = []; if ($shouldFork) { wordfence::status(4, 'info', __("Forking during malware scan to ensure continuity.", 'wordfence')); $forkObj->fork(); } } } wordfenceMalwareScanFile::markCompleteBatch($completed); } $this->writeScanningStatus(); if ($options['scansEnabled_fileContentsGSB']) { wordfence::status(2, 'info', __('Asking Wordfence to check URLs against malware list.', 'wordfence')); $hooverResults = $this->urlHoover->getBaddies(); if($this->urlHoover->errorMsg){ $this->errorMsg = $this->urlHoover->errorMsg; if ($backtrackLimit !== false) { ini_set('pcre.backtrack_limit', $backtrackLimit); } return false; } $this->urlHoover->cleanup(); foreach($hooverResults as $file => $hresults){ $record = wordfenceMalwareScanFile::fileForPath($file); $dataForFile = $this->dataForFile($file, $record->realPath); foreach($hresults as $result){ if(preg_match('/wfBrowscapCache\.php$/', $file)){ continue; } if (empty($result['URL'])) { continue; } if ($result['badList'] == 'wordfence-dbl') { $this->addResult(array( 'type' => 'file', 'severity' => wfIssues::SEVERITY_CRITICAL, 'ignoreP' => $record->realFile, 'ignoreC' => md5_file($record->realPath), 'shortMsg' => __('File contains suspected malware URL: ', 'wordfence') . esc_html($record->getDisplayPath()), 'longMsg' => __('This file contains a URL that is currently listed on Wordfence\'s domain blocklist. The URL is: ', 'wordfence') . esc_html($result['URL']), 'data' => array_merge(array( 'file' => $file, 'realFile' => $record->realPath, 'shac' => $record->SHAC, 'badURL' => $result['URL'], 'gsb' => 'wordfence-dbl', 'highSense' => $options['scansEnabled_highSense'] ), $dataForFile), )); } } } } wfUtils::afterProcessingFile(); wordfence::status(4, 'info', __('Finalizing malware scan results', 'wordfence')); if (!empty($this->results)) { $safeFiles = $this->scanEngine->isSafeFile(array_keys($this->resultFilesByShac)); foreach ($safeFiles as $hash) { foreach ($this->resultFilesByShac[$hash] as $file) unset($this->results[$file]); } } if ($backtrackLimit !== false) { ini_set('pcre.backtrack_limit', $backtrackLimit); } return $this->results; } protected function writeScanningStatus() { wordfence::status(2, 'info', sprintf( /* translators: 1. Number of fils. 2. Seconds in millisecond precision. */ __('Scanned contents of %1$d additional files at %2$.2f per second', 'wordfence'), $this->totalFilesScanned, ($this->totalFilesScanned / (microtime(true) - $this->startTime)) )); } protected function addResult($result) { if (isset($result['data']['file'])) { $file = $result['data']['file']; $existing = array_key_exists($file, $this->results) ? $this->results[$file] : null; if ($existing === null || $existing['severity'] > $result['severity']) { $this->results[$file] = $result; if (isset($result['data']['shac'])) { $shac = $result['data']['shac']; if (!array_key_exists($shac, $this->resultFilesByShac)) $this->resultFilesByShac[$shac] = []; $this->resultFilesByShac[$shac][] = $file; } } } else { $this->results[] = $result; } } /** * @param string $file * @return array */ private function dataForFile($file, $fullPath = null) { $loader = $this->scanEngine->getKnownFilesLoader(); $data = array(); if ($isKnownFile = $loader->isKnownFile($file)) { if ($loader->isKnownCoreFile($file)) { $data['cType'] = 'core'; } else if ($loader->isKnownPluginFile($file)) { $data['cType'] = 'plugin'; list($itemName, $itemVersion, $cKey) = $loader->getKnownPluginData($file); $data = array_merge($data, array( 'cName' => $itemName, 'cVersion' => $itemVersion, 'cKey' => $cKey )); } else if ($loader->isKnownThemeFile($file)) { $data['cType'] = 'theme'; list($itemName, $itemVersion, $cKey) = $loader->getKnownThemeData($file); $data = array_merge($data, array( 'cName' => $itemName, 'cVersion' => $itemVersion, 'cKey' => $cKey )); } } $suppressDelete = false; $canRegenerate = false; if ($fullPath !== null) { $bootstrapPath = wordfence::getWAFBootstrapPath(); $htaccessPath = wfUtils::getHomePath() . '.htaccess'; $userIni = ini_get('user_ini.filename'); $userIniPath = false; if ($userIni) { $userIniPath = wfUtils::getHomePath() . $userIni; } if ($fullPath == $htaccessPath) { $suppressDelete = true; } else if ($userIniPath !== false && $fullPath == $userIniPath) { $suppressDelete = true; } else if ($fullPath == $bootstrapPath) { $suppressDelete = true; $canRegenerate = true; } } $localFile = realpath($this->path . $file); $isWPConfig = $localFile === ABSPATH . 'wp-config.php'; $data['canDiff'] = $isKnownFile; $data['canFix'] = $isKnownFile && !$isWPConfig; $data['canDelete'] = !$isKnownFile && !$canRegenerate && !$suppressDelete && !$isWPConfig; $data['canRegenerate'] = $canRegenerate && !$isWPConfig; $data['wpconfig'] = $isWPConfig; return $data; } } /** * Convenience class for interfacing with the wfFileMods table. * * @property string $filename * @property string $filenameMD5 * @property string $newMD5 * @property string $SHAC * @property string $stoppedOnSignature * @property string $stoppedOnPosition * @property string $isSafeFile */ class wordfenceMalwareScanFile { protected $_filename; protected $_realPath; protected $_filenameMD5; protected $_filenameMD5Hex; protected $_newMD5; protected $_shac; protected $_stoppedOnSignature; protected $_stoppedOnPosition; protected $_isSafeFile; protected static function getDB() { static $db = null; if ($db === null) { $db = new wfDB(); } return $db; } public static function countRemaining() { $db = self::getDB(); return $db->querySingle("SELECT COUNT(*) FROM " . wfDB::networkTable('wfFileMods') . " WHERE oldMD5 != newMD5 AND knownFile = 0"); } public static function files($limit = 500) { $db = self::getDB(); $result = $db->querySelect("SELECT filename, real_path, filenameMD5, HEX(newMD5) AS newMD5, HEX(SHAC) AS SHAC, stoppedOnSignature, stoppedOnPosition, isSafeFile FROM " . wfDB::networkTable('wfFileMods') . " WHERE oldMD5 != newMD5 AND knownFile = 0 AND isSafeFile != '1' LIMIT %d", $limit); $files = array(); foreach ($result as $row) { $files[] = new wordfenceMalwareScanFile($row['filename'], $row['real_path'], $row['filenameMD5'], $row['newMD5'], $row['SHAC'], $row['stoppedOnSignature'], $row['stoppedOnPosition'], $row['isSafeFile']); } return $files; } public static function fileForPath($file) { $db = self::getDB(); $row = $db->querySingleRec("SELECT filename, real_path, filenameMD5, HEX(newMD5) AS newMD5, HEX(SHAC) AS SHAC, stoppedOnSignature, stoppedOnPosition, isSafeFile FROM " . wfDB::networkTable('wfFileMods') . " WHERE filename = '%s'", $file); return new wordfenceMalwareScanFile($row['filename'], $row['real_path'], $row['filenameMD5'], $row['newMD5'], $row['SHAC'], $row['stoppedOnSignature'], $row['stoppedOnPosition'], $row['isSafeFile']); } public function __construct($filename, $realPath, $filenameMD5, $newMD5, $shac, $stoppedOnSignature, $stoppedOnPosition, $isSafeFile) { $this->_filename = $filename; $this->_realPath = $realPath; $this->_filenameMD5 = $filenameMD5; $this->_filenameMD5Hex = bin2hex($filenameMD5); $this->_newMD5 = $newMD5; $this->_shac = strtoupper($shac); $this->_stoppedOnSignature = $stoppedOnSignature; $this->_stoppedOnPosition = $stoppedOnPosition; $this->_isSafeFile = $isSafeFile; } public function __get($key) { switch ($key) { case 'filename': return $this->_filename; case 'realPath': return $this->_realPath; case 'filenameMD5': return $this->_filenameMD5; case 'filenameMD5Hex': return $this->_filenameMD5Hex; case 'newMD5': return $this->_newMD5; case 'SHAC': return $this->_shac; case 'stoppedOnSignature': return $this->_stoppedOnSignature; case 'stoppedOnPosition': return $this->_stoppedOnPosition; case 'isSafeFile': return $this->_isSafeFile; } } public function __toString() { return "Record [filename: {$this->filename}, realPath: {$this->realPath}, filenameMD5: {$this->filenameMD5}, newMD5: {$this->newMD5}, stoppedOnSignature: {$this->stoppedOnSignature}, stoppedOnPosition: {$this->stoppedOnPosition}]"; } public static function markCompleteBatch($records) { if (empty($records)) return; $db = self::getDB(); $db->update( wfDB::networkTable('wfFileMods'), [ 'oldMD5' => 'newMD5' ], [ 'filenameMD5' => array_map(function($record) { return $record->filenameMD5Hex; }, $records) ], [ 'filenameMD5' => 'UNHEX(%s)' ] ); } public function updateStoppedOn($signature, $position) { $this->_stoppedOnSignature = $signature; $this->_stoppedOnPosition = $position; $db = self::getDB(); $db->queryWrite("UPDATE " . wfDB::networkTable('wfFileMods') . " SET stoppedOnSignature = '%s', stoppedOnPosition = %d WHERE filenameMD5 = UNHEX(%s)", $this->stoppedOnSignature, $this->stoppedOnPosition, $this->filenameMD5Hex); } public function getDisplayPath() { if (preg_match('#(^|/)..(/|$)#', $this->filename)) return $this->realPath; return $this->filename; } }Hacking Attempt